001    /*
002     * Copyright 2004-2005 Stephen J. McConnell.
003     * Copyright 1999-2004 The Apache Software Foundation
004     *
005     * Licensed  under the  Apache License,  Version 2.0  (the "License");
006     * you may not use  this file  except in  compliance with the License.
007     * You may obtain a copy of the License at
008     *
009     *   http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed  under the  License is distributed on an "AS IS" BASIS,
013     * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
014     * implied.
015     *
016     * See the License for the specific language governing permissions and
017     * limitations under the License.
018     */
019    package net.dpml.i18n;
020    
021    import java.lang.ref.WeakReference;
022    import java.util.HashMap;
023    import java.util.Locale;
024    
025    /**
026     * Manager for resources.
027     *
028     * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
029     * @version 1.0.0
030     */
031    public final class ResourceManager
032    {
033        /**
034         * Permission needed to clear complete cache.
035         */
036        private static final RuntimePermission CLEAR_CACHE_PERMISSION =
037            new RuntimePermission( "i18n.clearCompleteCache" );
038    
039        /**
040         * Resource lookup table.
041         */
042        private static final HashMap RESOURCES = new HashMap();
043    
044        /**
045         * Retrieve resource with specified basename.
046         *
047         * @param baseName the basename
048         * @return the Resources
049         */
050        public static final Resources getBaseResources( final String baseName )
051        {
052            return getBaseResources( baseName, null );
053        }
054    
055        /**
056         * Retrieve resource with specified basename.
057         *
058         * @param baseName the basename
059         * @param classLoader the classLoader to load resources from
060         * @return the Resources
061         */
062        public static final synchronized Resources getBaseResources( 
063          final String baseName, final ClassLoader classLoader )
064        {
065            Resources resources = getCachedResource( baseName );
066            if( null == resources )
067            {
068                resources = new Resources( baseName, classLoader );
069                putCachedResource( baseName, resources );
070            }
071    
072            return resources;
073        }
074    
075        /**
076         * Retrieve resource with specified basename.
077         *
078         * @param baseName the basename
079         * @param locale the locale
080         * @param classLoader the classLoader to load resources from
081         * @return the Resources
082         */
083        public static final synchronized Resources getBaseResources( 
084          final String baseName, final Locale locale, final ClassLoader classLoader )
085        {
086            Resources resources = getCachedResource( baseName + "_" + locale.hashCode() );
087            if( null == resources )
088            {
089                resources = new Resources( baseName, locale, classLoader );
090                putCachedResource( baseName + "_" + locale.hashCode(), resources );
091            }
092    
093            return resources;
094        }
095    
096        /**
097         * Clear the cache of all resources currently loaded into the
098         * system. This method is useful if you need to dump the complete
099         * cache and because part of the application is reloading and
100         * thus the resources may need to be reloaded.
101         *
102         * <p>Note that the caller must have been granted the
103         * "i18n.clearCompleteCache" {@link RuntimePermission} or
104         * else a security exception will be thrown.</p>
105         *
106         * @throws SecurityException if the caller does not have
107         *                           permission to clear cache
108         */
109        public static final synchronized void clearResourceCache()
110            throws SecurityException
111        {
112            final SecurityManager sm = System.getSecurityManager();
113            if( null != sm )
114            {
115                sm.checkPermission( CLEAR_CACHE_PERMISSION );
116            }
117    
118            RESOURCES.clear();
119        }
120    
121        /**
122         * Cache specified resource in weak reference.
123         *
124         * @param baseName the resource key
125         * @param resources the resources object
126         */
127        private static final synchronized void putCachedResource( 
128          final String baseName, final Resources resources )
129        {
130            RESOURCES.put( baseName, new WeakReference( resources ) );
131        }
132    
133        /**
134         * Retrieve cached resource.
135         *
136         * @param baseName the resource key
137         * @return resources the resources object
138         */
139        private static final synchronized Resources getCachedResource( final String baseName )
140        {
141            final WeakReference weakReference =
142                (WeakReference) RESOURCES.get( baseName );
143            if( null == weakReference )
144            {
145                return null;
146            }
147            else
148            {
149                return (Resources) weakReference.get();
150            }
151        }
152    
153        /**
154         * Retrieve resource for specified name.
155         * The basename is determined by name postfixed with ".Resources".
156         *
157         * @param name the name to use when looking up resources
158         * @return the Resources
159         */
160        public static final Resources getResources( final String name )
161        {
162            return getBaseResources( name + ".Resources" );
163        }
164    
165        /**
166         * Retrieve resource for specified Classes package.
167         * The basename is determined by name of classes package
168         * postfixed with ".Resources".
169         *
170         * @param clazz the Class
171         * @return the Resources
172         */
173        public static final Resources getPackageResources( final Class clazz )
174        {
175            return getBaseResources( getPackageResourcesBaseName( clazz ), clazz.getClassLoader() );
176        }
177    
178        /**
179         * Retrieve resource for specified Classes package.
180         * The basename is determined by name of classes package
181         * postfixed with ".Resources".
182         *
183         * @param clazz the Class
184         * @param locale the locale
185         * @return the Resources
186         */
187        public static final Resources getPackageResources( final Class clazz, Locale locale )
188        {
189            return getBaseResources( getPackageResourcesBaseName( clazz ), locale, clazz.getClassLoader() );
190        }
191    
192        /**
193         * Retrieve resource for specified Class.
194         * The basename is determined by name of Class
195         * postfixed with "Resources".
196         *
197         * @param clazz the Class
198         * @return the Resources
199         */
200        public static final Resources getClassResources( final Class clazz )
201        {
202            return getBaseResources( getClassResourcesBaseName( clazz ), clazz.getClassLoader() );
203        }
204    
205        /**
206         * Retrieve resource for specified Class.
207         * The basename is determined by name of Class
208         * postfixed with "Resources".
209         *
210         * @param clazz the Class
211         * @param locale the requested Locale.
212         * @return the Resources
213         */
214        public static final Resources getClassResources( final Class clazz, Locale locale )
215        {
216            return getBaseResources( getClassResourcesBaseName( clazz ), locale, clazz.getClassLoader() );
217        }
218    
219        /**
220         * Retrieve resource basename for specified Classes package.
221         * The basename is determined by name of classes package
222         * postfixed with ".Resources".
223         *
224         * @param clazz the Class
225         * @return the resource basename
226         */
227        public static final String getPackageResourcesBaseName( final Class clazz )
228        {
229            final Package pkg = clazz.getPackage();
230    
231            String baseName;
232            if( null == pkg )
233            {
234                final String name = clazz.getName();
235                if( -1 == name.lastIndexOf( "." ) )
236                {
237                    baseName = "Resources";
238                }
239                else
240                {
241                    baseName = name.substring( 0, name.lastIndexOf( "." ) ) + ".Resources";
242                }
243            }
244            else
245            {
246                baseName = pkg.getName() + ".Resources";
247            }
248    
249            return baseName;
250        }
251    
252        /**
253         * Retrieve resource basename for specified Class.
254         * The basename is determined by name of Class
255         * postfixed with "Resources".
256         *
257         * @param clazz the Class
258         * @return the resource basename
259         */
260        public static final String getClassResourcesBaseName( final Class clazz )
261        {
262            return clazz.getName() + "Resources";
263        }
264    
265        /**
266         * Private Constructor to block instantiation.
267         */
268        private ResourceManager()
269        {
270        }
271    }